﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using CaroLibraly;
using CaroLibrary;

namespace CaroBoard
{
    public delegate void EndGame();
    public partial class BoardUI : UserControl
    {
        private AI ai;
        private int crTime;
        private Board board;
        private Image imgX, imgO;
        private Rectangle curBoardRec;//Hình chữ nhật của board
        public bool AllowPlay;
        public bool EndGame;
        public char PlayerSymbol
        {
            set { this.board.PlayerSymbol = value; }
            get { return this.board.PlayerSymbol; }
        }
        public event EndGame HaveWinner;
        public BoardUI()
        {
            InitializeComponent();

            this.board = new Board(49, 25);
            this.crTime = 0;
            this.imgX = new Bitmap(CaroBoard.Properties.Resources.x);
            this.imgO = new Bitmap(CaroBoard.Properties.Resources.o);
            this.curBoardRec = new Rectangle(0, 0, (this.board.NumberLines + 1) * this.board.CellSize, this.board.CellSize* (this.board.NumberLines + 1));
            this.AllowPlay = true;
            this.EndGame = false;
            this.ai = new AI(20, 1, true);//độ khó 1. Số ô 12
            //this.gameTime.Start();
        }

        /// <summary>
        /// Cập nhật lại bảng trong phạm vi ấn
        /// </summary>
        /// <param name="p"></param>
        private void UpdateBoard(Point e)
        {
            int x, y, x1, y1;

            x = e.X - this.board.CellSize;
            y = e.Y - this.board.CellSize;
            x1 = e.X + this.board.CellSize;
            y1 = e.Y + this.board.CellSize;

            x = x < 0 ? 0 : x;
            y = y < 0 ? 0 : y;
            x1 = x1 < 0 ? 0 : x1;
            y1 = y1 < 0 ? 0 : y1;

            Rectangle rec = new Rectangle(x, y, x1, y1);

            this.Invalidate(rec);//Cập nhật trong hình chữ nhật này            
        }

        /// <summary>
        /// Cập nhật lại toàn bộ bàn cờ
        /// </summary>
        private void UpdateAllBoard()
        {
            this.Invalidate(this.curBoardRec);
        }

        /// <summary>
        /// Đổi lượt chơi
        /// </summary>
        public void SwitchPlayer1()
        {
            this.AllowPlay = !this.AllowPlay;
        }

        /// <summary>
        /// Tiếp tục chơi?
        /// </summary>
        private void Continue()
        {
            DialogResult diaRes = MessageBox.Show("Yes = Chơi trận mới", "Chơi trận mới", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            if (diaRes == DialogResult.Yes)
            {
                this.EndGame = false;
                this.board = new Board(49, 25);
                this.UpdateAllBoard();
            }
        }

        /// <summary>
        /// Bắt đầu chơi
        /// </summary>
        public void StartGame()
        {
            this.gameTime.Start();
        }

        //Cập nhật bàn cờ
        public void Fuck(int px, int py, char symbol)
        {
            if (this.EndGame)
            {
                this.Continue();
                return;
            }

            //Lấy ô được chọn
            int x = px / this.board.CellSize + 1;
            int y = py / this.board.CellSize;

            if (this.board.GetCell(x, y) == ' ')//Nếu ô đó chưa được đánh
                    this.board.SetCell(x, y, symbol);

            //Cập nhật bảng
            if (this.board.CheckWin().Win)
                this.UpdateAllBoard();//Vẽ gạch dài nên cập nhật toàn khung
            else
                this.UpdateBoard(new Point(px, py));//Chỉ cần cập nhật xung quanh điểm vừa ấn
        }

        /// <summary>
        /// Vẽ bàn cờ
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaint(PaintEventArgs e)
        {
            int x = 0, y = this.statusToolStrip.Height, size = this.board.NumberLines;
            Point p1, p2;

            #region Vẽ khung
            //Vẽ đường ngang
            for (int i = 0; i <= size; i++)
            {
                p1 = new Point(0, y);
                p2 = new Point(this.Width, y);
                e.Graphics.DrawLine(Pens.Black, p1, p2);
                y += this.board.CellSize;
            }
            //Vẽ đường dọc
            for (int i = 0; i < size; i++)
            {
                p1 = new Point(x, this.statusToolStrip.Height);
                p2 = new Point(x, this.Height);
                e.Graphics.DrawLine(Pens.Black, p1, p2);
                x += this.board.CellSize;
            }
            #endregion

            #region Hiển thị o-x lên bàn
            for (int i = 1; i <= this.board.NumberLines; i++)
            {
                for (int j = 1; j <= this.board.NumberLines; j++)
                {
                    p1 = new Point((i - 1) * this.board.CellSize, j * this.board.CellSize);
                    //x = (e.X / this.board.CellSize + 1);
                    //y = ((e.Y - this.statusToolStrip.Height) / this.board.CellSize + 1);

                    p1.Y += this.statusToolStrip.Height - this.board.CellSize;
                    switch (this.board.GetCell(i, j))
                    {
                        case 'x':
                            e.Graphics.DrawImage(this.imgX, p1);
                            break;
                        case 'o':
                            e.Graphics.DrawImage(this.imgO, p1);
                            break;
                        case '0':
                            e.Graphics.DrawImage(new Bitmap(this.board.CellSize, this.board.CellSize), p1);
                            break;
                    }
                }
            }
            #endregion

            #region Kiểm tra xem có người thắng chưa
            Line l = this.board.CheckWin();
            if (l.Win)
            {
                e.Graphics.DrawLine(new Pen(Color.Blue, 5), l.Start, l.End);
                this.EndGame = true;
                MessageBox.Show(this.board.CurrentTurn.Game.ToString() + " thắng!");
                if (this.HaveWinner != null)
                    this.HaveWinner();
            }
            #endregion

            base.OnPaint(e);
        }

        /// <summary>
        /// Hiển thị tọa độ ô đang được di chuột qua
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BoardUI_MouseMove(object sender, MouseEventArgs e)
        {
            string x = (e.X / this.board.CellSize + 1).ToString();
            string y = ((e.Y - this.statusToolStrip.Height) / this.board.CellSize + 1).ToString();

            x = x.Length == 1 ? "0" + x : x;
            y = y.Length == 1 ? "0" + y : y;
            this.lblMosePosition.Text = x + ":" + y;
        }

        /// <summary>
        /// Hiển thị thời gian chơi
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void gameTime_Tick(object sender, EventArgs e)
        {
            this.crTime++;
            string minutes = (this.crTime / 60).ToString();
            string secord = (this.crTime - int.Parse(minutes) * 60).ToString();
            minutes = minutes.Length == 1 ? "0" + minutes : minutes;
            secord = secord.Length == 1 ? "0" + secord : secord;
            this.lblTime.Text = minutes.ToString() + ":" + secord.ToString();
        }

        /// <summary>
        /// Sự kiện ấn vào một ô
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BoardUI_MouseClick(object sender, MouseEventArgs e)
        {
            if (this.AllowPlay)//Lượt mình thì bấm vào mới cho chơi
            {
                this.Fuck(e.X, e.Y, this.PlayerSymbol);
                //this.AllowPlay = false;//Chơi xong thì nghỉ
                if (!this.EndGame)
                {
                    //Máy đánh
                    char symbol = this.PlayerSymbol == 'x' ? 'o' : 'x';
                    Position p = this.ai.Solve(ref this.board, symbol);
                    Point po = Position.PositionToPoint(p, this.board.CellSize);
                    this.Fuck(po.X, po.Y, symbol);
                }
            }
        }
    }
}
